var Effects = {
	Effect: function(params) {
		var me = this;

		var d = new Date();
		this.UniqueId = 'Effect' + d.getTime();

		this.Id     = params.id;
		this.Name   = params.name;
		this.Target = params.target;

		this.Stun      = params.stun || 0;
		this.Disorient = params.disorient || 0;
		this.Banish    = params.banish || 0;
		this.Knockdown = params.knockdown || 0;

		this.MaxStacks      = params.max_stacks || 1;
		this.UniqueToAll    = params.unique_to_all || 0;
		this.UniqueToCaster = params.unique_to_caster || 1;

		this.ArmorMultiplyBase      = params.armor_multiply_base || 0;
		this.PowerMultiplyBase      = params.power_multiply_base || 0;
		this.HitPointsMultiplyBase  = params.hit_points_multiply_base || 0;
		this.ArmorAdd               = params.armor_add || 0;
		this.PowerAdd               = params.power_add || 0;
		this.HitPointsAdd           = params.hit_points_add || 0;
		this.ArmorMultiplyTotal     = params.armor_multiply_total || 0;
		this.PowerMultiplyTotal     = params.power_multiply_total || 0;
		this.HitPointsMultiplyTotal = params.hit_points_multiply_total || 0;

		this.Duration = params.duration || 0;
		this.Stacks   = params.stacks || 1;
		this.Interval = params.interval || null;
		this.Caster   = params.caster || null

		this.OnPeriodic = params.periodic || null;
		this.OnApply    = params.apply || null;
		this.OnFade     = params.fade || null;
		this.OnDispel   = params.dispel || null;

		this.FadeTimeout;
		this.PeriodicTimeout;

		var collection;
		this.Fade = function() {
			me.FadeTimeout.pause();
			if ( me.PeriodicTimeout ) me.PeriodicTimeout.pause();
			delete me.FadeTimeout;
			delete me.PeriodicTimeout;
			if ( me.OnFade ) me.OnFade({caster: me.Caster, target: me.Target});
			collection.Remove(me.UniqueId);
			Log({type: 'Effects.Effect.Fade', effect: me});
		};

		this.Dispel = function(params) {
			if ( me.OnDispel ) me.OnDispel({caster: me.Caster, target: me.Target, dispeler: params.caster});
			Log({type: 'Effects.Effect.Dispel', effect: me, params: params});
			me.Fade();
		};

		this.Periodic = function() {
			me.PeriodicTimeout.reset();
			me.OnPeriodic({caster: me.Caster, target: me.Target});
		};

		this.Renew = function(params) {
			var duration = params.duration;
			var time_left = me.FadeTimeout.left();
			if ( duration > time_left ) me.FadeTimeout.reset(duration);
			Log({type: 'Effects.Effect.Renew', effect: me, params: params});
		};

		this.AddStacks = function(params) {
			var stacks = params.stacks;
			var duration = params.duration;
			var time_left = me.FadeTimeout.left();
			me.Stacks += stacks;
			if ( me.Stacks > me.MaxStacks ) me.Stacks = me.MaxStacks;
			if ( duration > time_left ) me.FadeTimeout.reset(duration);
			Log({type: 'Effects.Effect.AddStacks', effect: me, params: params});
		};

		this.Init = function(c) {
			collection = c;

			if ( me.OnApply ) me.OnApply({caster: me.Caster, target: me.Target});

			if ( me.OnPeriodic && me.Interval ) {
				me.PeriodicTimeout = new Timeout(me.Periodic, me.Interval * 1000);
			}

			if ( me.Duration ) {
				me.FadeTimeout = new Timeout(me.Fade, me.Duration * 1000);
			}
		};
	},
	Collection: function(caster) {
		var me = this;
		this.Caster = caster;
		this.Items = {};
		this.HasAny = function(name) {
			for ( var key in me.Items ) {
				var item = me.Items[key];
				if ( item[name] ) return true;
			}
			return false;
		};

		this.GetAll = function(name) {
			var retval = 0;
			for ( var key in me.Items ) {
				var item = me.Items[key];
				retval += item[name];
			}
			return retval;
		};

		/*this.Stun      = function() { return property_any('Stun'); };
		this.Disorient = function() { return property_any('Disorient'); };
		this.Banish    = function() { return property_any('Banish'); };
		this.Knockdown = function() { return property_any('Knockdown'); };

		this.Jump = function() { return property_any('Jump'); };
		this.Distance = function() { return property_any('Distance'); };

		this.ArmorMultiplyBase      = function() { return property_all('ArmorMultiplyBase'); };
		this.PowerMultiplyBase      = function() { return property_all('PowerMultiplyBase'); };
		this.HitPointsMultiplyBase  = function() { return property_all('HitPointsMultiplyBase'); };
		this.ArmorAdd               = function() { return property_all('ArmorAdd'); };
		this.PowerAdd               = function() { return property_all('PowerAdd'); };
		this.HitPointsAdd           = function() { return property_all('HitPointsAdd'); };
		this.ArmorMultiplyTotal     = function() { return property_all('ArmorMultiplyTotal'); };
		this.PowerMultiplyTotal     = function() { return property_all('PowerMultiplyTotal'); };
		this.HitPointsMultiplyTotal = function() { return property_all('HitPointsMultiplyTotal'); };*/

		this.Get = function(id, caster) {
			for ( var key in me.Items ) {
				var item = me.Items[key];
				if ( typeof caster != 'undefined' && item.Caster == caster && item.Id == id ) {
					return item;
				} else if ( typeof caster == 'undefined' && item.Id == id ) {
					return item;
				}
			}
			return null;
		};

		this.Add = function(params) {
			params.target = me.Caster;
			var effect = new Effects.Effect(params);
			if ( effect.UniqueToAll ) {
				var e = me.Get(effect.Id);
				if ( e ) {
					e.Renew(params);
					return true;
				}
			} else if ( effect.UniqueToCaster ) {
				var e = me.Get(effect.Id, params.caster);
				if ( e ) {
					e.Renew(params);
					return true;
				}
			}

			me.Items[effect.UniqueId] = effect;
			effect.Init(me);
			me.Caster.UpdateStats();
			Log({type: 'Effects.Collection.Add', effect: effect});
		};

		this.Remove = function(uid) {
			delete(me.Items[uid]);
		};
	},
	Debuffs: {
		stun: {
			id: 'stun',
			name: 'Stun',
			stun: true
		},
		knockdown: {
			id: 'knockdown',
			name: 'Knockdown',
			duration: 30,
			knockdown: true
		},
		ignite: {
			id: 'ignite',
			type: 'debuff',
			name: 'Ignite',
			duration: 9.1,
			interval: 3,
			periodic: function(params) {
				//Rules.ApplyDamage({damage: .1, name: 'Ignite', caster: params.caster, target: params.target});
				console.log('damage');
			}
		}
	},
	Buffs: {
		strengthen: {
			id: 'strengthen',
			name: 'Strengthen',
			power_multiply_total: .1,
			duration: 30
		},
		fortify: {
			id: 'fortify',
			name: 'Fortify',
			hit_points_add: 100,
			duration: 3
		}
	}
};

var Equipment = {
	Helms: {
		MithrilHelm: function() {
			var gear = new CharacterMod({Type: GearTypes.Head, Name: 'Mithril Helm', ArmorValue: 500});
			return gear;
		}
	}
};
